-
Couldn't load subscription status.
- Fork 73
Added asymmetric encrypt and decrypt to Mbed Crypto provider #196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
This PR won't pass CI until |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good!
| * Ionut Mihalcea (@ionut-arm) | ||
| * Hugues de Valon (@hug-dev) | ||
| * Jesper Brynolf (@Superhepper) | ||
| * Samuel Bailey (@sbailey-arm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🌞
Cargo.toml
Outdated
| psa-crypto = { version = "0.2.1" , default-features = false, features = ["with-mbed-crypto"], optional = true } | ||
| psa-crypto = { version = "0.2.2" , default-features = false, features = ["with-mbed-crypto"], optional = true } | ||
| zeroize = { version = "1.1.0", features = ["zeroize_derive"] } | ||
| secrecy = { version = "0.6.0", features = ["serde"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? I didn't see any direct uses of it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, I have removed it. Wonder if there's a clippy setting to catch that...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WIP it seems
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That PR only provides the functionality of cargo-udeps in upstream tools. You can install it today!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @est31! We should definitely add that on our CIs!
| let salt_buff = match &op.salt { | ||
| Some(salt) => Some(salt.as_slice()), | ||
| None => None, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this what you're trying to achieve here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that's quite it. op.salt is an Option<Zeroizing<Vec<u8>>> and I need salt_buff to be Option<&[u8]>. There may still be some more concise way of writing it that I'm not aware of though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh! I thought that since Zeroizing implements Deref, it would work - actually, it seems as_deref is what I should've recommended, though it doesn't solve the whole problem either - op.salt.as_deref() yields Option<&Vec<u8>>
| } | ||
| Err(error) => { | ||
| let error = ResponseStatus::from(error); | ||
| format_error!("Encrypt status: {}", error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The format_error macro doesn't need the {} part of the "format string", that gets added inside the macro!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that's why the log outputs have been a bit odd...!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about in this case?
format_error!(
"Error {} when opening a persistent Mbed Crypto key.",
e
);There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops! I didn't notice that one when it went in... I wrote format_error to always log in the same format "Brief description of problem; error: {}" - the last bit is only written when the config flag for verbose logging is on. You can probably change that to ("Failed to open persistent Mbed Crypto key", e)
| } | ||
| Err(error) => { | ||
| // When dropped, will zero buffer incase anything was written before error | ||
| let _ = Secret::new(plaintext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Easier/quicker to just plaintext.zeroize() here (though you need to import the Zeroize trait).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
huh, I didn't know you could do that 🤯! How does it work? plaintext is a regular Vec<u8>' and I can't see anything obvious in the documentation that states Zeroizableis implemented forVec. Is it u8implementsDefaultIsZeros, so implements Zeroizablein the blanket implementation andVec` 'inherits' (derefs?) that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Zeroize is implemented on Vecs - it's actually what you were using in the other PR when doing plaintext.zeroize() for the protobuf types - those types don't use Zeroizing or anything from the crate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah... 🤦♂️
| fn asym_encrypt_verify_decrypt_with_rsa_crate() { | ||
| let key_name = String::from("asym_encrypt_verify_decrypt_with_rsa_crate"); | ||
| let mut client = TestClient::new(); | ||
|
|
||
| client.generate_rsa_encryption_keys_rsapkcs1v15crypt(key_name.clone()).unwrap(); | ||
| let pub_key = client.export_public_key(key_name.clone()).unwrap(); | ||
|
|
||
| let rsa_pub_key = RSAPublicKey::from_pkcs1(&pub_key).unwrap(); | ||
| let ciphertext = rsa_pub_key.encrypt(&mut OsRng, PaddingScheme::new_pkcs1v15_encrypt(), &PLAINTEXT_MESSAGE).unwrap(); | ||
|
|
||
| let plaintext = client.asymmetric_decrypt_message_with_rsapkcs1v15( | ||
| key_name.clone(), | ||
| ciphertext, | ||
| ).unwrap(); | ||
|
|
||
| assert_eq!(&PLAINTEXT_MESSAGE[..], &plaintext[..]); | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙆♂️ niiiiiice!
95fc26b to
79a3a14
Compare
a678fcf to
163bbd6
Compare
| if client.provider() != Some(ProviderID::MbedCrypto) { | ||
| // Not supported by current provider | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a neater way of doing this?
Would be nice if the tests could check which operations the current provider supports and only test those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can always put an #[cfg(feature = "mbed-crypto-provider")] on the test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is in the e2e crate... Hmmm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the if is 100% correct anyway, because you could have multiple providers set up and the client chooses a different one, doesn't mean the Mbed Crypto one isn't available. Maybe we should change the set_provider method (on the test client) to check if the provider actually exists, and returns an error if not. Then we can check on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
client chooses a different one
Are the tests not done in isolation? As in, there will only ever be one provider at once during testing?
Maybe we should change the set_provider method (on the test client) to check if the provider actually exists, and returns an error if not. Then we can check on that.
So have set_provider check basic_client.list_providers to see if that provider exists (in this case, MbedCrypto) and if it does, it returns Ok and we can run the tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the tests not done in isolation? As in, there will only ever be one provider at once during testing?
Yeah, that's true, this is in the per_provider test thing - forget that.
I think we can do it in another way, actually, makes it more scalable - call list_opcodes and check if the operation you want is supported. If it isn't, return. It's not ideal because it will still appear as a test even when it's not supported, but there's no need to do anything to enable the test when you implement it in some new provider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can do it in another way, actually, makes it more scalable - call list_opcodes and check if the operation you want is supported. If it isn't, return. It's not ideal because it will still appear as a test even when it's not supported, but there's no need to do anything to enable the test when you implement it in some new provider.
That sounds more like what I was thinking. The other two solutions don't deal with the fact that the tests are still run either. Could do with a way of forcing text output even if --show-output isn't specified, so we can at least say 'Hey, this provider doesn't actually support this operation'. I can have a poke tomorrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it might be worth to change this check to:
if client.list_opcodes(client.provider().unwrap())?.contains(Opcode::PsaAsymmetricEncrypt) {
return;
}We could even create a method out of that snippet in the client:
fn is_operation_supported(&self, op: Opcode) -> bool {
}1f9f841 to
4b2fa81
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot! That looks very good. A few comments but otherwise it's ok.
| * Ionut Mihalcea (@ionut-arm) | ||
| * Hugues de Valon (@hug-dev) | ||
| * Jesper Brynolf (@Superhepper) | ||
| * Samuel Bailey (@sbailey-arm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🌞
| if client.provider() != Some(ProviderID::MbedCrypto) { | ||
| // Not supported by current provider | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it might be worth to change this check to:
if client.list_opcodes(client.provider().unwrap())?.contains(Opcode::PsaAsymmetricEncrypt) {
return;
}We could even create a method out of that snippet in the client:
fn is_operation_supported(&self, op: Opcode) -> bool {
}| app_name: ApplicationName, | ||
| op: psa_asymmetric_encrypt::Operation, | ||
| ) -> Result<psa_asymmetric_encrypt::Result> { | ||
| info!("Mbed Provider - Asym Encrypt"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think those info! are not needed now that we have the ingress/egress trace everywhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should they be removed from the other operations too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't mind 👀
| }) | ||
| } | ||
| Err(error) => { | ||
| plaintext.zeroize(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good point! Do you think, even in case of error, it might contain some decrypted data? Does the spec say anything about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm it doesn't mention it in the spec that I can see. A quick look at the mbedtls code shows that it only copies into plaintext buffer if successful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I reckon that is the safe, default, behaviour that you would expect. We can remove the zeroize here I think.
44f6795 to
e45d0e0
Compare
Signed-off-by: Samuel Bailey <[email protected]>
e45d0e0 to
599d8d1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adressing the comments!
| app_name: ApplicationName, | ||
| op: psa_sign_hash::Operation, | ||
| ) -> Result<psa_sign_hash::Result> { | ||
| info!("Pkcs11 Provider - Asym Sign"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thanks for removing those as well.
Signed-off-by: Samuel Bailey [email protected]